########################################################################
#  Searx-Qt - Lightweight desktop application for Searx.
#  Copyright (C) 2020-2022  CYBERDEViL
#
#  This file is part of Searx-Qt.
#
#  Searx-Qt is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  Searx-Qt is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
########################################################################


from PyQt5.QtCore import QObject, pyqtSignal

from searxqt.themes import Themes
from searxqt.core.instances import Stats2
from searxqt.core import log


class General:
    def serialize():
        return {
            'logLevel': log.LogLevel,
            'themes': Themes.serialize()
        }

    def deserialize(data):
        # Populate / re-populate user and system themes
        Themes.populate()
        themesData = data.get('themes', {})
        if themesData:
            Themes.deserialize(themesData)

        # Log level
        logLevel = data.get('logLevel', None)
        if logLevel is not None:
            log.LogLevel = logLevel
        else:
            log.LogLevel = log.LogLevels.QUIET


class SettingsModel(QObject):
    changed = pyqtSignal()

    def __init__(self, requestSettings, parent=None):
        QObject.__init__(self, parent=parent)

        self._requests = RequestSettingsModel(requestSettings)
        self._stats2 = None

        self._requests.changed.connect(self.changed)

    def loadSettings(self, data, stats2=True):
        self.requests.data = data.get('requests', {})

        if self._stats2:
            self._stats2.deleteLater()
            self._stats2 = None

        if stats2:
            self._stats2 = SearxStats2Model()
            stats2Data = data.get('stats2', {})
            self.stats2.loadSettings(stats2Data)

        General.deserialize(data.get('general', {}))

    def saveSettings(self):
        if self._stats2:
            return {
                'general': General.serialize(),
                'requests': self.requests.data,
                'stats2': self.stats2.saveSettings()
            }
        return {
            'general': General.serialize(),
            'requests': self.requests.data,
        }

    @property
    def requests(self): return self._requests

    @property
    def stats2(self): return self._stats2


class SearxStats2Model(QObject):
    changed = pyqtSignal()

    def __init__(self, parent=None):
        QObject.__init__(self, parent=parent)
        self._backupUrl = Stats2.URL

    def loadSettings(self, data):
        self.url = data.get('url', self._backupUrl)

    def saveSettings(self):
        return {
            'url': self.url
        }

    def reset(self):
        self.url = self._backupUrl

    @property
    def url(self):
        return Stats2.URL

    @url.setter
    def url(self, url):
        Stats2.URL = url
        self.changed.emit()


class RequestSettingsModel(QObject):
    changed = pyqtSignal()

    # @param requestSettings: TODO
    # @type requestSettings: core.requests.RequestSettings
    def __init__(self, requestSettings, parent=None):
        QObject.__init__(self, parent=parent)
        self._settings = requestSettings

    def __changed(self):
        self._settings.updateRequestKwargs()
        self.changed.emit()

    @property
    def data(self):
        return self._settings.getData()

    @data.setter
    def data(self, data):
        self._settings.setData(data)

    @property
    def extraHeaders(self):
        return self._settings.extraHeaders

    @property
    def verifySSL(self):
        return self._settings.verifySSL

    @verifySSL.setter
    def verifySSL(self, state):
        self._settings.verifySSL = state
        self.__changed()

    @property
    def timeout(self):
        return self._settings.timeout

    @timeout.setter
    def timeout(self, seconds):
        self._settings.timeout = seconds
        self.__changed()

    @property
    def maxSize(self):
        return self._settings.maxSize

    @maxSize.setter
    def maxSize(self, size):
        self._settings.maxSize = size
        self.__changed()

    @property
    def chunkSize(self):
        return self._settings.chunkSize

    @chunkSize.setter
    def chunkSize(self, size):
        self._settings.chunkSize = size
        self.__changed()

    @property
    def proxyEnabled(self):
        return self._settings.proxyEnabled

    @proxyEnabled.setter
    def proxyEnabled(self, state):
        self._settings.proxyEnabled = state
        self.__changed()

    @property
    def proxyHost(self):
        return self._settings.proxyHost

    @proxyHost.setter
    def proxyHost(self, host):
        self._settings.proxyHost = host
        self.__changed()

    @property
    def proxyProtocol(self):
        return self._settings.proxyProtocol

    @proxyProtocol.setter
    def proxyProtocol(self, protocol):
        self._settings.proxyProtocol = protocol
        self.__changed()

    @property
    def proxyDNS(self):
        return self._settings.proxyDNS

    @proxyDNS.setter
    def proxyDNS(self, state):
        self._settings.proxyDNS = state
        self.__changed()

    @property
    def useragents(self):
        return self._settings.useragents

    @useragents.setter
    def useragents(self, strList):
        """
        @param strList: A string with user-agents, separated by a new line.
                        May be empty.
        @type strList: str
        """
        self._settings.useragents.clear()
        for ua in strList:
            self._settings.useragents.append(ua)
        self.__changed()

    @property
    def randomUserAgent(self):
        return self._settings.randomUserAgent

    @randomUserAgent.setter
    def randomUserAgent(self, state):
        """
        @param state: True to select random user-agent for each request
                      If False it will select the first user-agent. When
                      the user-agents list is empty the send string will
                      be also empty.
        @type state: bool
        """
        self._settings.randomUserAgent = state
        self.__changed()
